import randomBytes from "../../randombytes";
import BN from "../../bn.js";
import MillerRabin from "../../miller-rabin";
findPrime.simpleSieve = simpleSieve;
findPrime.fermatTest = fermatTest;
var TWENTYFOUR = new BN(24);
var millerRabin = new MillerRabin();
var ONE = new BN(1);
var TWO = new BN(2);
var FIVE = new BN(5);
var SIXTEEN = new BN(16);
var EIGHT = new BN(8);
var TEN = new BN(10);
var THREE = new BN(3);
var SEVEN = new BN(7);
var ELEVEN = new BN(11);
var FOUR = new BN(4);
var TWELVE = new BN(12);
var primes = null;
function _getPrimes() {
    if (primes !== null)
        return primes;
    var limit = 0x100000;
    var res = [];
    res[0] = 2;
    for (var i = 1, k = 3; k < limit; k += 2) {
        var sqrt = Math.ceil(Math.sqrt(k));
        for (var j = 0; j < i && res[j] <= sqrt; j++)
            if (k % res[j] === 0)
                break;
        if (i !== j && res[j] <= sqrt)
            continue;
        res[i++] = k;
    }
    primes = res;
    return res;
}
function simpleSieve(p) {
    var primes = _getPrimes();
    for (var i = 0; i < primes.length; i++)
        if (p.modn(primes[i]) === 0) {
            if (p.cmpn(primes[i]) === 0) {
                return true;
            }
            else {
                return false;
            }
        }
    return true;
}
function fermatTest(p) {
    var red = BN.mont(p);
    return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0;
}
function findPrime(bits, gen) {
    if (bits < 16) {
        // this is what openssl does
        if (gen === 2 || gen === 5) {
            return new BN([0x8c, 0x7b]);
        }
        else {
            return new BN([0x8c, 0x27]);
        }
    }
    gen = new BN(gen);
    var num, n2;
    while (true) {
        num = new BN(randomBytes(Math.ceil(bits / 8)));
        while (num.bitLength() > bits) {
            num.ishrn(1);
        }
        if (num.isEven()) {
            num.iadd(ONE);
        }
        if (!num.testn(1)) {
            num.iadd(TWO);
        }
        if (!gen.cmp(TWO)) {
            while (num.mod(TWENTYFOUR).cmp(ELEVEN)) {
                num.iadd(FOUR);
            }
        }
        else if (!gen.cmp(FIVE)) {
            while (num.mod(TEN).cmp(THREE)) {
                num.iadd(FOUR);
            }
        }
        n2 = num.shrn(1);
        if (simpleSieve(n2) && simpleSieve(num) &&
            fermatTest(n2) && fermatTest(num) &&
            millerRabin.test(n2) && millerRabin.test(num)) {
            return num;
        }
    }
}
export default findPrime;
